#include "ftp_client.h"




void error(const char *msg) {
    perror(msg);
    exit(EXIT_FAILURE);
}

// 设置非阻塞模式
int set_non_blocking(int sockfd) {
    int flags = _ftp_fcntl(sockfd, F_GETFL, 0);
    if (flags == -1) return -1;
    return _ftp_fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
}

// 设置套接字超时
int set_socket_timeout(int sockfd, int seconds) {
    struct timeval tv;
    tv.tv_sec = seconds;
    tv.tv_usec = 0;
    if (_ftp_setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)) < 0) {
        perror("setsockopt");
        return -1;
    }
    return 0;
}

int connect_to_ftp_server(const char *hostname, int port) {
    int sockfd;
    struct sockaddr_in serv_addr;

    sockfd = _ftp_socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) error("ERROR opening socket");

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = _ftp_htons(port);

    if (inet_pton(AF_INET, hostname, &serv_addr.sin_addr) <= 0) {
        error("Invalid address/ Address not supported");
    }

    if (_ftp_connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        error("Connection Failed");
    }
    // 设置超时
    if (set_socket_timeout(sockfd, 30) < 0) {
        error("Failed to set socket timeout");
    }

    return sockfd;
}


// 从套接字读取响应
char *read_response(int sockfd) {
    char *response = (char *)malloc(MAXLINE * sizeof(char));
    if (response == NULL) error("Memory allocation failed");

    int n;
    n = _ftp_recv(sockfd, response, MAXLINE - 1, 0);
    if (n < 0) {
        if (errno != EAGAIN && errno != EWOULDBLOCK) {
            error("ERROR reading from socket");
        } else {
            response[0] = '\0';
        }
    } else {
        response[n] = '\0';
    }

    return response;
}


void send_command(int sockfd, const char *command) {
    if (_ftp_send(sockfd, command, strlen(command), 0) < 0) {
        error("ERROR writing to socket");
    }
    _ftp_send(sockfd, CRLF, 2, 0);
}

void login(int sockfd, const char *username, const char *password) {
    char cmd[128];
    char *response;
    sprintf(cmd, "USER %s", username);
    send_command(sockfd, cmd);
    response = read_response(sockfd);
    printf("%s", response);
    free(response);  // 释放内存

    sprintf(cmd, "PASS %s", password);
    send_command(sockfd, cmd);
    response = read_response(sockfd);
    printf("%s", response);
    free(response);  // 释放内存
}


void set_binary_mode(int sockfd) {
    send_command(sockfd, "TYPE I");
    char *response = read_response(sockfd);
    printf("%s", response);
    free(response);
}

void passive_mode(int sockfd, struct sockaddr_in *data_addr, int *data_port) {
    send_command(sockfd, "PASV");
    char *response = read_response(sockfd);
    printf("%s", response);

    // Parse the response for the data connection details
    char *start = strstr(response, "(");
    char *end = strstr(response, ")");
    if (start && end) {
        start += 1;
        *end = '\0';
        char *tokens[6];
        char *saveptr;
        tokens[0] = strtok_r(start, ",", &saveptr);
        for (int i = 1; i < 6; ++i) {
            tokens[i] = strtok_r(NULL, ",", &saveptr);
        }
        data_addr->sin_family = AF_INET;
        data_addr->sin_addr.s_addr = htonl(atoi(tokens[0]) << 24 | atoi(tokens[1]) << 16 | atoi(tokens[2]) << 8 | atoi(tokens[3]));
        *data_port = atoi(tokens[4]) << 8 | atoi(tokens[5]); // 将端口号从网络字节序转换为主机字节序
    } else {
        error("Failed to parse PASV response");
    }
    free(response);
}

void download_file(int sockfd, const char *remote_filename, const char *local_filename) {
    set_binary_mode(sockfd);  // Set binary mode

    struct sockaddr_in data_addr;
    int data_port;
    passive_mode(sockfd, &data_addr, &data_port);

    int data_sockfd = connect_to_ftp_server(inet_ntoa(data_addr.sin_addr), data_port);

    char cmd[128];
    sprintf(cmd, "RETR %s", remote_filename);
    send_command(sockfd, cmd);

    FILE *file = fopen(local_filename, "wb");
    if (file == NULL) error("Could not open file for writing");

    char buffer[MAXLINE];
    int n;
    while ((n = _ftp_recv(data_sockfd, buffer, MAXLINE, 0)) > 0) {
        fwrite(buffer, 1, n, file);
    }

    if (n < 0) {
        error("ERROR reading from socket");
    }

    fclose(file);
    close(data_sockfd);


    char *response = read_response(sockfd);
    printf("%s", response);
    free(response);  // 释放内存

}

void upload_file(int sockfd, const char *local_filename, const char *remote_filename) {
    set_binary_mode(sockfd);  // Set binary mode

    struct sockaddr_in data_addr;
    int data_port;
    passive_mode(sockfd, &data_addr, &data_port);

    int data_sockfd = connect_to_ftp_server(inet_ntoa(data_addr.sin_addr), data_port);

    char cmd[128];
    sprintf(cmd, "STOR %s", remote_filename);
    send_command(sockfd, cmd);

    FILE *file = fopen(local_filename, "rb");
    if (file == NULL) error("Could not open file for reading");

    char buffer[MAXLINE];
    int n;
    while ((n = fread(buffer, 1, MAXLINE, file)) > 0) {
        if (_ftp_send(data_sockfd, buffer, n, 0) < 0) error("ERROR writing to socket");
    }

    fclose(file);
    close(data_sockfd);


    char *response = read_response(sockfd);
    printf("%s", response);
    free(response);  // 释放内存
}

#if 0
int main(int argc, char *argv[]) {
    if (argc < 5) {
        fprintf(stderr, "Usage: %s <hostname> <username> <password> <command> [args...]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    const char *hostname = argv[1];
    const char *username = argv[2];
    const char *password = argv[3];
    const char *command = argv[4];

    int sockfd = connect_to_ftp_server(hostname, FTP_PORT);
    printf("%s", read_response(sockfd));

    login(sockfd, username, password);

    if (strcmp(command, "download") == 0) {
        if (argc < 7) {
            fprintf(stderr, "Usage: %s <hostname> <username> <password> download <remote_filename> <local_filename>\n", argv[0]);
            exit(EXIT_FAILURE);
        }
        const char *remote_filename = argv[5];
        const char *local_filename = argv[6];
        download_file(sockfd, remote_filename, local_filename);
    } else if (strcmp(command, "upload") == 0) {
        if (argc < 7) {
            fprintf(stderr, "Usage: %s <hostname> <username> <password> upload <local_filename> <remote_filename>\n", argv[0]);
            exit(EXIT_FAILURE);
        }
        const char *local_filename = argv[5];
        const char *remote_filename = argv[6];
        upload_file(sockfd, local_filename, remote_filename);
    } else {
        fprintf(stderr, "Unknown command: %s\n", command);
        exit(EXIT_FAILURE);
    }

    // 退出并关闭连接
    send_command(sockfd, "QUIT");
    printf("%s", read_response(sockfd));

    close(sockfd);
    return 0;
}
#endif